package org.voidness.oje2d.gui;

import java.util.Vector;

import org.voidness.oje2d.GLColor;
import org.voidness.oje2d.gui.docks.DockedWindow;

/** The GUI (graphical user interface) engine. */
public class GuiEngine {
    /** The singleton instance of the GUI engine */
    public static GuiEngine instance = null;

    /** The list of windows */
    private Vector<Window> windowList = null;

    /**
     * Get the connection for the single instance of the GUI engine.
     * 
     * @return The GUI engine instance
     */
    public static GuiEngine getInstance() {
        if (instance == null) {
            instance = new GuiEngine();
        }
        return instance;
    }

    /**
     * Default private constructor.
     */
    private GuiEngine() {
        windowList = new Vector<Window>();
    }

    /**
     * Defines a mouse button press event.
     * 
     * @param mButton The button pressed
     */
    public void mousePressed(int mButton) {
        // Cycle the window list and check if the click gets any of them
        // If it does, save the maximum window index (the one most on top)
        // and that's the one we clicked
        int lastIndex = -1;
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);
            if (window.hasMouseOver() && i > lastIndex)
                lastIndex = i;

            // Send the click to the window widget
            // window.mousePressed(mButton);
        }

        // If we actually grabbed any window...
        if (lastIndex != -1) {
            // This is the window we want
            Window window = (Window) windowList.elementAt(lastIndex);

            // Set the window as grabbed
            window.setGrabbed(true);

            // Reorder the window list, (i.e., set this one on top)
            if (!window.isFixed()) {
                windowList.remove(window);
                windowList.add(window);
            }

            // Send the click to the window widget
            window.mousePressed(mButton);
        }

        // System.out.println("Mouse button pressed: " + mButton);
    }

    /**
     * Defines a mouse button release event.
     * 
     * @param mButton The button released
     */
    public void mouseReleased(int mButton) {
        // Release all windows from beeing grabbed
        int lastIndex = -1;
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);
            if (window.hasMouseOver() && i > lastIndex)
                lastIndex = i;

            // Set grabbed false to all
            window.setGrabbed(false);

            // Send the key released event
            // window.mouseReleased(mButton);
        }

        // If we have the one on top
        if (lastIndex != -1) {
            // This is the window we want
            Window window = (Window) windowList.elementAt(lastIndex);

            // Send the key released event
            window.mouseReleased(mButton);
        }

        // System.out.println("Mouse button released: " + mButton);
    }

    /**
     * Fires the key pressed event.
     * 
     * @param mKey The key beeing pressed
     * @param mChar The correspondent character
     */
    public void keyPressed(int mKey, char mChar) {
        // TODO: In the future only send key events to currently focused widget

        // Send the key pressed event to the window on top
        if (windowList.size() > 0) {
            Window window = (Window) windowList.lastElement();
            window.keyPressed(mKey, mChar);
        }
    }

    /**
     * Fires the key released event.
     * 
     * @param mKey The key beeing pressed
     */
    public void keyReleased(int mKey) {
        // TODO: In the future only send key events to currently focused widget

        // Send the key released event to the window on top
        if (windowList.size() > 0) {
            Window window = (Window) windowList.lastElement();
            window.keyReleased(mKey);
        }
    }

    /**
     * If the mouse's left button is down, cycle through the window list and, if
     * any is beeing grabbed, update it's position.
     */
    public void update() {
        // Cycle the window list and update both the position and the events
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);

            // Check if mouse down. If so, see which window is beeing grabbed
            // and update it's position
            // if (mouseLeftDown && window.isGrabbed())
            window.updatePosition();

            // Remember to update all windows so we can check events in the
            // child widgets as well.
            // window.update();
        }
    }

    /**
     * Draws the windows in the window list.
     */
    public void draw() {
        // Cycle the list of windows and draw them
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);

            if (!(window instanceof DockedWindow))
                window.draw(GLColor.WHITE);
            // Note: To keep the widget draw(GLColor mColor) happy, we
            // pass a white color in here.
        }

        // Cycle the list of windows and draw the docked on top
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);
            if (window instanceof DockedWindow)
                window.draw(GLColor.WHITE);
            // Note: To keep the widget draw(GLColor mColor) happy, we
            // pass a white color in here.
        }

        // Cycle the list of windows and draw all the tooltips
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);
            window.drawToolTips();
        }
    }

    /**
     * Adds a new window to the GUI engine.
     * 
     * @param mWindow The window to add
     */
    public void addWindow(Window mWindow) {
        windowList.add(mWindow);
    }

    public void removeWindow(Widget mWindow) {
        windowList.remove(mWindow);
    }

    public void removeAll() {
        windowList.removeAllElements();
    }

    public int getNumberOfWindows() {
        return windowList.size();
    }

    public void clearFocus() {
        // Cycle the list of windows and draw all the tooltips
        for (int i = 0; i < windowList.size(); i++) {
            Window window = (Window) windowList.elementAt(i);
            window.setFocus(false);
        }
    }
}